--- dlls/ntoskrnl.exe/ntoskrnl-old.c	2007-09-30 23:01:33.000000000 +0200
+++ dlls/ntoskrnl.exe/ntoskrnl.c	2007-10-03 13:37:52.000000000 +0200
@@ -30,6 +30,7 @@
 #define WIN32_NO_STATUS
 #include "windef.h"
 #include "winternl.h"
+#include "winioctl.h"
 #include "excpt.h"
 #include "ddk/wdm.h"
 #include "wine/unicode.h"
@@ -131,8 +132,10 @@
     PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
     NTSTATUS status;
     LARGE_INTEGER count;
+    VOID* shared_buf = NULL;
 
-    TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );
+    TRACE( "ioctl %x device %p in_buf %p in_size %u out_buf %p out_size %u\n",
+               code, device, in_buff, in_size, out_buff, *out_size );
 
     /* so we can spot things that we should initialize */
     memset( &irp, 0x55, sizeof(irp) );
@@ -140,24 +143,97 @@
     memset( &mdl, 0x77, sizeof(mdl) );
 
     irp.RequestorMode = UserMode;
-    irp.AssociatedIrp.SystemBuffer = in_buff;
-    irp.UserBuffer = out_buff;
-    irp.MdlAddress = &mdl;
+
+    /* --- buffer handling depending on ioctl access method ---
+       To avoid confusion "in_buf" should mentally be seen as "control" buffer,
+       which is usually a small, optional buffer that might contain a control
+       structure with useful information for the device driver.
+       "out_buf" should actually be seen as (large) "data transfer" buffer
+       which the device driver reads from and writes to */
+    switch(code & 3)
+    {
+    case METHOD_BUFFERED:
+
+        /* METHOD_BUFFERED from driver perspective:
+           Only one buffer: Irp->AssociatedIrp.SystemBuffer
+           The driver reads input data from this buffer and writes output data
+           to the same buffer, overwriting the input data. */
+
+        /* The size of this buffer is equal to the size of the larger of the
+           two buffers */
+        shared_buf = HeapAlloc( GetProcessHeap(), 0,
+                           (in_size > *out_size) ? in_size : *out_size);
+
+        memcpy( shared_buf, in_buff, in_size);
+        irp.AssociatedIrp.SystemBuffer = shared_buf;
+        irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
+        irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
+        break;
+
+    case METHOD_IN_DIRECT:
+   
+        /* METHOD_IN_DIRECT from driver perspective:
+           Same use of Irp->AssociatedIrp.SystemBuffer as METHOD_BUFFERED - 
+           except anything written to this buffer is lost.
+           Copying data back to user-mode buffers is not supported. */
+        shared_buf = HeapAlloc( GetProcessHeap(), 0, in_size);
+
+        memcpy( shared_buf, in_buff, in_size);
+        irp.AssociatedIrp.SystemBuffer = shared_buf;
+        irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
+        irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
+
+        /* For out_buff (user mode buffer) an MDL is allocated.
+           The MDL is address is stored in Irp->MdlAddress. */
+
+        /* FIXME: wineserver has to copy the contents of out_buf from
+                  calling process! */
+        irp.MdlAddress = &mdl;
+        mdl.Next = NULL;
+        mdl.Size = 0;
+        mdl.StartVa = out_buff;
+        mdl.ByteCount = *out_size;
+        mdl.ByteOffset = 0;
+        break;
+
+    case METHOD_OUT_DIRECT:
+
+        /* METHOD_OUT_DIRECT from driver perspective:
+           Same use of Irp->AssociatedIrp.SystemBuffer as METHOD_BUFFERED */
+        shared_buf = HeapAlloc( GetProcessHeap(), 0, in_size);
+
+        memcpy( shared_buf, in_buff, in_size);
+        irp.AssociatedIrp.SystemBuffer = shared_buf;
+        irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
+        irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
+
+        /* out_buff contains data that is written by the driver and
+           read by the user-mode application when the request is completed.
+           For out_buff (user mode buffer) an MDL is allocated.
+           The MDL is address is stored in Irp->MdlAddress. */
+        irp.MdlAddress = &mdl;
+        mdl.Next = NULL;
+        mdl.Size = 0;
+        mdl.StartVa = out_buff;
+        mdl.ByteCount = *out_size;
+        mdl.ByteOffset = 0;
+        break;
+ 
+    case METHOD_NEITHER:
+
+        /* not really recommended method, no data transfer buffers! */ 
+        irp.UserBuffer = out_buff;
+    
+        irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
+        break;
+    }
+  
     irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp;
 
     irpsp.MajorFunction = IRP_MJ_DEVICE_CONTROL;
-    irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
-    irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
     irpsp.Parameters.DeviceIoControl.IoControlCode = code;
-    irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
     irpsp.DeviceObject = device;
 
-    mdl.Next = NULL;
-    mdl.Size = 0;
-    mdl.StartVa = out_buff;
-    mdl.ByteCount = *out_size;
-    mdl.ByteOffset = 0;
-
     device->CurrentIrp = &irp;
 
     KeQueryTickCount( &count );  /* update the global KeTickCount */
@@ -172,7 +248,46 @@
         DPRINTF( "%04x:Ret  driver dispatch %p (device=%p,irp=%p) retval=%08x\n",
                  GetCurrentThreadId(), dispatch, device, &irp, status );
 
-    *out_size = irp.IoStatus.u.Status ? 0 : irp.IoStatus.Information;
+    /* completion buffer handling depending on ioctl access method */
+    *out_size = 0; 
+    switch(code & 3)
+    {
+    case METHOD_BUFFERED:
+
+        /* If IoStatus.Status = STATUS_SUCCESS, then
+           copy the number of bytes specified by IoStatus.Information from
+           Irp->AssociatedIrp.SystemBuffer into out_buff */
+        if( irp.IoStatus.u.Status == STATUS_SUCCESS)
+        {
+            memcpy( out_buff, irp.AssociatedIrp.SystemBuffer, irp.IoStatus.Information);
+            *out_size = irp.IoStatus.Information;
+        }
+        break;
+
+    case METHOD_IN_DIRECT:
+
+        /* irp.IoStatus.Information actually represents the number of bytes
+           of the lpOutBuffer actually written to the device
+           (user mode app might want to see this) */
+        *out_size = irp.IoStatus.Information;
+        break;
+
+    case METHOD_OUT_DIRECT:
+
+        /* irp.IoStatus.Information actually represents the number of bytes
+           of the lpOutBuffer actually read from the device */
+        *out_size = irp.IoStatus.Information;
+        break;
+
+    case METHOD_NEITHER:
+
+        /* nothing to report - no data transfer buffers! */ 
+        break;
+    }
+
+    if( shared_buf)
+        HeapFree( GetProcessHeap(), 0, shared_buf);
+
     return irp.IoStatus.u.Status;
 }
 
@@ -543,6 +658,90 @@
     return STATUS_SUCCESS;
 }
 
+/***********************************************************************
+ *           MmGetSystemRoutineAddress   (NTOSKRNL.EXE.@)
+ */
+PVOID WINAPI MmGetSystemRoutineAddress( PUNICODE_STRING SystemRoutineName )
+{
+    HMODULE mod;
+    STRING routineNameA;
+    PVOID addr = NULL;
+    
+    static const WCHAR ntoskrnlW[] = {'n','t','o','s','k','r','n','l','.','e','x','e','\0'}; 
+    static const WCHAR halW[] = {'h','a','l','.','d','l','l','\0'}; 
+    
+    if (!SystemRoutineName || !SystemRoutineName->Buffer|| !SystemRoutineName->Length)
+        return NULL; 
+
+    RtlUnicodeStringToAnsiString( &routineNameA, SystemRoutineName, TRUE);
+ 
+    /* system routine can be ntoskrnl.exe or hal.dll export */
+    mod = GetModuleHandleW( ntoskrnlW);
+    if (mod)
+    { 
+       addr = GetProcAddress( mod, routineNameA.Buffer);
+    }
+
+    if( !addr)
+    {
+       mod = GetModuleHandleW( halW);
+       if (mod)
+       { 
+          addr = GetProcAddress( mod, routineNameA.Buffer);
+       }
+    }
+    RtlFreeAnsiString( &routineNameA );
+
+    TRACE( "%s resolved to %p\n", debugstr_us(SystemRoutineName), addr);
+
+    return addr;
+}
+
+/***********************************************************************
+ *           MmMapIoSpace   (NTOSKRNL.EXE.@)
+ */
+PVOID WINAPI MmMapIoSpace( PHYSICAL_ADDRESS PhysicalAddress,
+                         DWORD NumberOfBytes, DWORD CacheType)
+{
+    FIXME( "stub: 0x%08x%08x, %d, %d\n", PhysicalAddress.u.HighPart,
+        PhysicalAddress.u.LowPart, NumberOfBytes, CacheType);
+
+    /* The whole page mapping mechanism (page tables) and the concept
+       of paged vs. nonpaged pool does not exist in wine "kernel". */
+
+    /* NT either maps to non-paged area or allocates from non-paged pool.
+       If the system fails to find contigious space in a given range that
+       is sufficient for mapping MDLs, the call should fail.
+       Although this issue only exist if you map more than 4MB of space
+       (more than one page table can map -> need to find adjacent free entries
+       in page directories). */
+    return VirtualAlloc( NULL, NumberOfBytes, MEM_RESERVE|MEM_COMMIT,
+                        PAGE_READWRITE|PAGE_NOCACHE ); 
+}
+
+/***********************************************************************
+ *           MmUnmapIoSpace   (NTOSKRNL.EXE.@)
+ */
+void WINAPI MmUnmapIoSpace( PVOID BaseAddress, DWORD NumberOfBytes)
+{
+    FIXME( "stub: %p, %d\n", BaseAddress, NumberOfBytes);
+
+    /* The whole page mapping mechanism (page tables) and the concept of paged
+       vs. nonpaged pool does not exist in wine "kernel". (see MmMapIoSpace )*/
+    VirtualFree( BaseAddress, 0, MEM_RELEASE );
+}
+
+/***********************************************************************
+ *           MmGetPhysicalAddress (NTOSKRNL.EXE.@)
+ */
+ULONGLONG WINAPI MmGetPhysicalAddress( PVOID BaseAddress)
+{
+    FIXME( "stub: %p\n", BaseAddress);
+   
+    /* No page tables available - though that might be emulated some day.
+       Malware like GameGuard needs page table directories to be emulated */
+    return (ULONGLONG) (DWORD) BaseAddress;
+}
 
 /*****************************************************
  *           DllMain
--- dlls/ntoskrnl.exe/ntoskrnl.exe-old.spec	2007-09-30 23:40:19.000000000 +0200
+++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec	2007-10-03 13:35:40.000000000 +0200
@@ -673,9 +673,9 @@
 @ stub MmFreeMappingAddress
 @ stdcall MmFreeNonCachedMemory(ptr long)
 @ stub MmFreePagesFromMdl
-@ stub MmGetPhysicalAddress
+@ stdcall MmGetPhysicalAddress(ptr)
 @ stub MmGetPhysicalMemoryRanges
-@ stub MmGetSystemRoutineAddress
+@ stdcall MmGetSystemRoutineAddress(ptr)
 @ stub MmGetVirtualForPhysical
 @ stub MmGrowKernelStack
 @ stub MmHighestUserAddress
@@ -688,7 +688,7 @@
 @ stub MmLockPagableDataSection
 @ stub MmLockPagableImageSection
 @ stub MmLockPagableSectionByHandle
-@ stub MmMapIoSpace
+@ stdcall MmMapIoSpace( long long long long)
 @ stub MmMapLockedPages
 @ stub MmMapLockedPagesSpecifyCache
 @ stub MmMapLockedPagesWithReservedMapping
@@ -718,7 +718,7 @@
 @ stub MmTrimAllSystemPagableMemory
 @ stub MmUnlockPagableImageSection
 @ stub MmUnlockPages
-@ stub MmUnmapIoSpace
+@ stdcall MmUnmapIoSpace( ptr long)
 @ stub MmUnmapLockedPages
 @ stub MmUnmapReservedMapping
 @ stub MmUnmapVideoDisplay
